#include "ChatWindow.h"
#include <wx/sysopt.h>
#include <wx/imaglist.h>
#include "../StdUserInterfaceModule/Icons.h"
#include "../../core/Impp.h"

namespace Impp
{

BEGIN_EVENT_TABLE(ChatWindow, wxFrame)
  EVT_CLOSE(ChatWindow::closed)
  EVT_NOTEBOOK_PAGE_CHANGED(ID_TABS, ChatWindow::onPageChaned)
  EVT_ACTIVATE(ChatWindow::onActivate)
  EVT_BUTTON(ID_CLOSE_WINDOW,ChatWindow::onCloseWindow)
END_EVENT_TABLE()

/*
 * ChatWindow
 */

ChatWindow::ChatWindow(StdChatWindowModule* module) :
	wxFrame(NULL, ID_CHATWIN, _T("ChatWindow")),
	lastAdded(NULL),
	buttonList(module->getButtonList())
{
	wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);

	iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
	if(ui == NULL){
		wxLogError(wxT("ChatWindow: No userinterface found, can not create Chatwindow"));
	}

	pages = new ImppNotebook(this,ID_TABS);
	pages->SetImageList(ui->getIcons()->getStatusImageList());

	Connect(EVT_NOTEBOOK_PAGE_CLOSED,NotebookPageClosedEventHandler(ChatWindow::onPageClose));

	Impp* impp = Impp::exemplar();
	impp->Connect(EVT_BUDDY_AVATAR_CHANGED,AvatarChangedEventHandler(ChatWindow::onAvatarChanged), NULL, this);
	impp->Connect(EVT_FILE_TRANSFARE,FileTransfareEventHandler(ChatWindow::onIncomingFile), NULL, this);
	impp->Connect(EVT_MESSAGE_CALLBACK,MessageCallbackEventHandler(ChatWindow::onMessageCallback), NULL, this);
	impp->Connect(EVT_BUDDY_STATUS_CHANGED,StatusEventHandler(ChatWindow::onStatusChanged), NULL, this);
	impp->Connect(EVT_MESSAGE_READ,MessageReadEventHandler(ChatWindow::onMessageRead), NULL, this);

	SetMinSize(wxSize(300,300));
	SetSize(wxSize(500,300));
	sizer->Add(pages,1,wxEXPAND);
	SetSizer(sizer);
    Layout();

    pages->Validate();


    wxAcceleratorEntry entries[1];
    entries[0].Set(wxACCEL_NORMAL,  WXK_ESCAPE, ID_CLOSE_WINDOW);
    wxAcceleratorTable accel(1, entries);
    SetAcceleratorTable(accel);


}

int ChatWindow::statusToIconsId(const Status & status){
	iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
	wxASSERT(ui != NULL);
	return ui->getIcons()->getStatusImageListId(status);
}

ChatWindow::~ChatWindow()
{
	Impp* impp = Impp::exemplar();
	impp->Disconnect(EVT_BUDDY_AVATAR_CHANGED,AvatarChangedEventHandler(ChatWindow::onAvatarChanged), NULL, this);
	impp->Disconnect(EVT_FILE_TRANSFARE,FileTransfareEventHandler(ChatWindow::onIncomingFile), NULL, this);
	impp->Disconnect(EVT_MESSAGE_CALLBACK,MessageCallbackEventHandler(ChatWindow::onMessageCallback), NULL, this);
	impp->Disconnect(EVT_BUDDY_STATUS_CHANGED,StatusEventHandler(ChatWindow::onStatusChanged), NULL, this);
	impp->Disconnect(EVT_MESSAGE_READ,MessageReadEventHandler(ChatWindow::onMessageRead), NULL, this);
}



ChatPanel* ChatWindow::show(Buddy* b, bool showWin, bool selectTab){
	ChatPanel* ret = NULL;

	//Look if the page is already open
	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
		if(pane->getBuddy()==b){
			//we found the tab, it is already open, so do we
			//have to make the tab selected?
			if(selectTab){
				pages->SetSelection(i);
			}
			ret = pane;
			break;
		}
	}

	if(ret==NULL){
		//Tab was not found so we create a new one:
		ret = new ChatPanel(this,pages,b);

		//Under mswin the color is ugly so use the std color
		#ifdef __WXMSW__
	    wxColour col = ret->GetBackgroundColour();
	    if (col.Ok()){
	    	ret->SetBackgroundColour(col);
	    }
		#endif

	    //workaround to ignore the pageChangedEvent of the new tab:
	    if(lastAdded != NULL){
	    	wxLogDebug(wxT("ChatWindow::show: lastAdded was not NULL, this shoud never happen!"));
	    }

	    //the new tab changed event is only throuen when the new tab became selected
	    //this is when select tab is true or it is the first tab
	    if(selectTab || pages->GetPageCount() == 0){
	    	lastAdded = ret;
	    }

	    //we have to insert the new page
	    //which icon shoud we use?
	    bool unreadMsgs = b->hasUnredMsg();
	    pages->AddPage(ret,b->getName(),selectTab,unreadMsgs ? ICON_NEW_MSG : statusToIconsId(b->getStatus()));

	    //under gtk the splitter only updates its position if the window is not visible...
	    //so this is a ugly workaround:
		#ifdef __WXGTK__
	    	bool isShown = IsShown();
	    	Show(false);
	    	Show(true);
	    	Show(isShown);
		#endif
		ret->initPane();

	}

	//so shoud we make the window visible if not?
	if(showWin){
		Show(true);
		Raise();
	}

	return ret;
}

void ChatWindow::close(Buddy* b){

	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* curChatPanel = static_cast<ChatPanel*>(pages->GetPage(i));
		if(curChatPanel->getBuddy()==b){
			pages->DeletePage(i);
			break;
		}
	}
	if(!pages->GetPageCount()){
		Show(false);
	}

	updateWindowTitle();


}

ChatPanel* ChatWindow::updateWindowTitle(){
	ChatPanel* pane = static_cast<ChatPanel*>(pages->GetCurrentPage());

	if(pane != NULL){
		SetTitle(pane->getBuddy()->getName());
		wxIcon icon;
		iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
		wxASSERT(ui != NULL);
		icon.CopyFromBitmap(ui->getIcons()->getStatusIcon(pane->getBuddy()->getStatus()));
		SetIcon(icon);
	}

	return pane;
}

void ChatWindow::showChatWindow(Buddy* buddy){
	show(buddy, true, true);
}

void ChatWindow::onPageClose(NotebookPageClosedEvent & event){
	ChatPanel* pane = dynamic_cast<ChatPanel*>(event.getPage());
	close(pane->getBuddy());
}

void ChatWindow::onPageChaned(wxNotebookEvent & event){
	event.Skip();
	ChatPanel* pane = updateWindowTitle();

	if(pane != lastAdded){
		//wxLogDebug(wxT("tab Changed and kill events"));
		pane->tabChanged();
	}else{
		//wxLogDebug(wxT("tab Changed but ignoring"));
		lastAdded = NULL;
	}

;
}

void ChatWindow::closed(wxCloseEvent & event){
	Show(false);
}

void ChatWindow::onMessageIn(MessageEvent & event){
	event.Skip();
	ChatPanel* pane = show(event.getBuddy(), false, false);
	pane->messageIn(event);
	setUnreadMsg(event.getBuddy(), true);
}

void ChatWindow::onTypingNotification(TypingNotificationEvent & event){
	event.Skip();
	ChatPanel* pane = show(event.getSender(), false, false);
	pane->typingNotification(event);

}

void ChatWindow::onMessageCallback(MessageCallbackEvent & event){
	event.Skip();
	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
		if(event.getBuddy()==pane->getBuddy()){
			pane->messageCallback(event);
			return;
		}
	}
}

void ChatWindow::onStatusChanged(StatusEvent & event){
	event.Skip();
	bool unreadMsgs = event.getBuddy()->hasUnredMsg();

	if(ChatPanel* curPane = static_cast<ChatPanel*>(pages->GetCurrentPage())){
		if(event.getBuddy() == curPane->getBuddy()){
			wxIcon icon;
			iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
			wxASSERT(ui != NULL);
			if(unreadMsgs){
				icon.CopyFromBitmap(ui->getIcons()->getSpecialBitmap(BITMAP_NEW_MSG));
			}else{
				icon.CopyFromBitmap(ui->getIcons()->getStatusIcon(event.getBuddy()->getStatus()));
			}
			SetIcon(icon);
		}
	}
	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
		if(event.getBuddy()==pane->getBuddy()){
			if(unreadMsgs){
				pages->SetPageImage(i,ICON_NEW_MSG);
			}else{
				pages->SetPageImage(i,statusToIconsId(event.getBuddy()->getStatus()));
			}
			pane->statusChanged(event);
			return;
		}
	}
}
void ChatWindow::onAvatarChanged(AvatarChangedEvent & event){
	event.Skip();
	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
		if(event.getBuddy()==pane->getBuddy()){
			pane->avatarChanged(event);
			return;
		}
	}
}

void ChatWindow::onIncomingFile(FileTransfareEvent & event){
	event.Skip();
	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
		if(event.getSender()==pane->getBuddy()){
			pane->IncomingFile(event);
			return;
		}
	}
}

void ChatWindow::onActivate(wxActivateEvent & event){
	if(pages->GetPageCount()>0){
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetCurrentPage());
		if(event.GetActive() && IsShownOnScreen()){
			pane->clearUnreadMsgs();
		}

	}
	event.Skip(true);
}

void ChatWindow::onMessageRead(MessageReadEvent & event){
	event.Skip();
	setUnreadMsg(event.getSender(), false);
}

void ChatWindow::setUnreadMsg(Buddy* buddy, bool unreadMsgs){
	if(pages->GetPageCount()>0){

		//Get cur Pane
		ChatPanel* curPane = static_cast<ChatPanel*>(pages->GetCurrentPage());

		//if we shoud announce unread msg but the curpage is the page and
		//the window is active we dont do it..
		if(unreadMsgs && IsActive() && IsShownOnScreen()  && curPane->getBuddy() == buddy){
			//so clear the unread msgs..
			Impp::exemplar()->processUnreadMessageRead(buddy);
		}else{
			//Set the Window Icon
			iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
			wxASSERT(ui != NULL);
			wxIcon icon;
			if(unreadMsgs){
				icon.CopyFromBitmap(ui->getIcons()->getSpecialBitmap(BITMAP_NEW_MSG));
			}else{
				icon.CopyFromBitmap(ui->getIcons()->getStatusIcon(curPane->getBuddy()->getStatus()));
			}
			SetIcon(icon);

			//Set the Tab Icon
			for (size_t i = 0; i < pages->GetPageCount(); ++i) {
				ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
				if(buddy==pane->getBuddy()){
					if(unreadMsgs){
						pages->SetPageImage(i,ICON_NEW_MSG);
					}else{
						pages->SetPageImage(i,statusToIconsId(buddy->getStatus()));
					}
					break;
				}
			}

			//Request UserAttention
			if(unreadMsgs && !IsActive()){
				RequestUserAttention(wxUSER_ATTENTION_ERROR);
			}
		}

	}

}

void ChatWindow::onCloseWindow(wxCommandEvent & event){
	Hide();
}

void ChatWindow::addActionButtion(const wxString & moduleName, const wxString & actionName, const wxString & title, const wxString & description){
	buttonList->addActionButton(moduleName,actionName,title,description);
}

ButtonList* ChatWindow::getButtonList(){
	return buttonList;
}

bool ChatWindow::hasBuddy(Buddy* buddy){
	//Look if the page is already open
	for (size_t i = 0; i < pages->GetPageCount(); ++i) {
		ChatPanel* pane = static_cast<ChatPanel*>(pages->GetPage(i));
		if(pane->getBuddy()==buddy){
			return true;
		}
	}
	return false;
}


}
